#include "stdafx.h"
#include "tileengine.h"

#include "map.h"
#include "camera.h"
#include "glc/clientstate.h"

#include <math.h>
#include "iostream"

namespace Demo {

class TileEnginePrivate
{
public:
    TileEnginePrivate()
    {
    }

    ~TileEnginePrivate()
    {
    }

    void initialization(SDL_Surface *screen)
    {
        m_screen = screen;
        m_camera.refresh();
        createMap();
    }

    void destroy()
    {
        m_map.destroy();
    }

    void renderMap()
    {
        m_map.render();
    }

    void onKeyUp(SDLKey key)
    {
        m_keys_pressed.erase(key);
    }

    void onKeyDown(SDLKey key)
    {
        m_keys_pressed.insert(key);
        switch (key)
        {
            case SDLK_RIGHT:
                break;
            case SDLK_d:
                break;
            case SDLK_LEFT:
                break;
            case SDLK_a:
                break;
            case SDLK_UP:
                break;
            case SDLK_w:
                break;
            case SDLK_DOWN:
                break;
            case SDLK_s:
                break;
            case SDLK_SPACE:
                break;
            case SDLK_LSHIFT:
                break;
            case SDLK_EQUALS:
                m_camera.zoomIn();
                break;
            case SDLK_MINUS:
                m_camera.zoomOut();
                break;
            default:
                break;
        }
    }

    bool onMouseDown(Core::MouseEvent const& event)
    {
        if (event.button == MouseButton_LEFT)
        {
            return detectMouseClick(event);
        }
        if (event.button == MouseButton_WHEELUP)
        {
            m_camera.zoomIn();
            return true;
        }
        if (event.button == MouseButton_WHEELDOWN)
        {
            m_camera.zoomOut();
            return true;
        }
        return false;
    }

    void onMouseMove(Core::MouseEvent const& event)
    {
        m_camera.turnAroundZ(event.diffX);
        m_camera.turnAroundX(event.diffY);
    }

    void onIdle()
    {
        if (m_keys_pressed.count(SDLK_w))
        {
            m_camera.shiftForward();
        }
        if (m_keys_pressed.count(SDLK_s))
        {
            m_camera.shiftBack();
        }
        if (m_keys_pressed.count(SDLK_a))
        {
            m_camera.shiftLeft();
        }
        if (m_keys_pressed.count(SDLK_d))
        {
            m_camera.shiftRight();
        }
        if (m_keys_pressed.count(SDLK_SPACE))
        {
            m_camera.shiftUp();
        }
        if (m_keys_pressed.count(SDLK_LSHIFT))
        {
            m_camera.shiftDown();
        }

    }

private:
    void createMap()
    {
        m_map.create(15, 15);
    }

    bool detectMouseClick(Core::MouseEvent const& event)
    {
        vec2d pointXY(event.x, event.y);
        vec3d pointInGameSpace = m_camera.unProject(pointXY);
        int cellXCoord = floor(pointInGameSpace.x + m_map.width() * 0.5);
        int cellYCoord = floor(pointInGameSpace.y + m_map.height() * 0.5);
        if (cellXCoord < 0 || cellXCoord >= m_map.width()
            || cellYCoord < 0 || cellYCoord >= m_map.height())
        {
            myDebug() << "Out: " << cellXCoord << " " << cellYCoord << "\n";
            return false;
        }

        myDebug() << "Inside: " << cellXCoord << " " << cellYCoord << "\n";
        return true;
    }

    Map m_map;
    Camera m_camera;
    SDL_Surface* m_screen;
    std::set<SDLKey> m_keys_pressed;
};

TileEngine::TileEngine()
    :d(new TileEnginePrivate())
{
}

TileEngine::~TileEngine()
{
}

void TileEngine::initialization(SDL_Surface *screen)
{
    glClearColor(1, 1, 1, 1);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);

    mat4d projection;
    projection.loadPerspective(60.0, double(screen->w) / double(screen->h), 1.0, 100.0);
    GLC::ClientState::loadProjection(projection);

    if (glGetError() != GL_NO_ERROR)
    {
        myDebug() << "OpenGL error occured in TileEngine::initialization()\n";
    }

    d->initialization(screen);

    draw();
}

void TileEngine::destroy()
{
    d->destroy();
}

void TileEngine::logic(const long &elapsedTimeMs)
{
    (void)elapsedTimeMs;
}

void TileEngine::draw()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    d->renderMap();
    SDL_GL_SwapBuffers();
}

void TileEngine::onKeyDown(SDLKey key)
{
    d->onKeyDown(key);
    draw();
    (void)key;
}

void TileEngine::onKeyUp(SDLKey key)
{
    d->onKeyUp(key);
    draw();
}

void TileEngine::onMouseDown(Core::MouseEvent event)
{
    if (d->onMouseDown(event))
        draw();
}

void TileEngine::onMouseMove(Core::MouseEvent event)
{
    d->onMouseMove(event);
    draw();
}

void TileEngine::onMouseUp(Core::MouseEvent event)
{
    (void)event;
}

void TileEngine::onIdle()
{
    d->onIdle();
    draw();
}

} // namespace Demo
